using System.Net.Sockets;
using System.Net;
using SharpChannel.Core.Packet;
using SharpChannel.Exceptions;
using SharpChannel.Util;
using log4net;

namespace SharpChannel.Core
{
    public class TcpClient
	{
        private static ILog log = LoggerHelper.GetLogger();

		private ClientSession _session;
		
		public event NewPacketHandler NewPacketReceived;

        private static readonly int RecieveTime = ConfigurationUtil.GetRecvTimeoutValue();


        public TcpClient(string ip=null, int port=0)
		{
		    if (string.IsNullOrEmpty(ip)) ip = ConfigurationUtil.GetConnectIP();
            if (port <= 0) port = ConfigurationUtil.GetConnectPort();
            log.InfoFormat("trying to connect to ip{0}, port{1}", ip, port);
			var socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
		    try
		    {
		        socket.Connect(new IPEndPoint(IPAddress.Parse(ip), port));
		    }
		    catch (SocketException ex)
		    {
                log.Error(string.Format("connect to ip{0}, port{1} failed", ip, port), ex);
		        throw new SharpChannelNetException(string.Format("connect to server{0}:{1} failed", ip, port), ex);
		    }
		    _session = new ClientSession(socket);
		}

		public void SendMessage(byte[] buffer)
		{
		    if (_session == null)
		    {
                throw new SharpChannelNetException("you are not connected to server!");
		    }
            LoggerHelper.GetLogger().DebugFormat("client has send {0} bytes to server.",_session.Send(buffer));
		    try
		    {
		        buffer = _session.ReceiveUntilDecode(RecieveTime);
		        if (buffer != null)
		        {
		            NewPacketReceived?.Invoke(this, new NewPacketArgs(buffer, _session));
		        }
		        else
		        {
                    LoggerHelper.GetLogger().Warn("nothing received.");
		        }
		    }
		    catch (SocketException ex)
		    {
		        _session = null;
		        throw new SharpChannelNetException("error occured:disconnect from server!", ex);
		    }
		}
		
		public void SendAndReiveMessage(byte[] buffer, out byte[] reciveBuffer){
		    if (_session == null)
		    {
                throw new SharpChannelNetException("you are not connected to server!");
		    }
            LoggerHelper.GetLogger().DebugFormat("client has send {0} bytes to server.",_session.Send(buffer));
		    try
		    {
		        reciveBuffer = _session.ReceiveUntilDecode(RecieveTime);
		        if (reciveBuffer != null)
		        {
                    LoggerHelper.GetLogger().DebugFormat("recived byte size:{0}", reciveBuffer.Length);
		        }
		        else
		        {
                    LoggerHelper.GetLogger().Warn("nothing received.");
		        }
		    }
		    catch (SocketException ex)
		    {
		        reciveBuffer = null;
		        _session = null;
                throw new SharpChannelNetException("error occured:disconnect from server!", ex);
		    }
		}

		public void SendMessage (string message)
		{
			var buffer = System.Text.Encoding.UTF8.GetBytes (message);
			SendMessage (buffer);
		}

        public void Close()
        {
            _session?.GetSocket().Close();
        }
	}
}

